#include "stdafx.h"
#include "log/consolechannel.hpp"
#include "charset/string.hpp"
using namespace JHCPP::charset;
#include "stdlib/bugcheck.hpp"
#include "stdlib/exception.hpp"
using namespace JHCPP::stdlib;
using namespace JHCPP::stdlib::jhException;
#include <iostream>

namespace JHCPP
{
	namespace log
	{
		//////////////////////////////////////////////////////////////////////////
		//CConsoleChannel
		//////////////////////////////////////////////////////////////////////////
		CMutex CConsoleChannel::m_mutex;

		CConsoleChannel::CConsoleChannel() : m_str(std::clog)
		{
		}

		CConsoleChannel::CConsoleChannel(std::ostream& str) : m_str(str)
		{
		}

		CConsoleChannel::~CConsoleChannel()
		{
		}

		void CConsoleChannel::log(const CMessage& msg)
		{
			CMutex::ScopedLock lock(m_mutex);

			m_str << msg.getText() << std::endl;
		}


		//////////////////////////////////////////////////////////////////////////
		//CColorConsoleChannel
		//////////////////////////////////////////////////////////////////////////
		CMutex CColorConsoleChannel::m_mutex;
		const std::string CColorConsoleChannel::CSI("\033[");

		CColorConsoleChannel::CColorConsoleChannel() : m_str(std::clog), m_enableColors(true)
		{
			initColors();
		}

		CColorConsoleChannel::CColorConsoleChannel(std::ostream& str) : m_str(str), m_enableColors(true)
		{
			initColors();
		}

		CColorConsoleChannel::~CColorConsoleChannel()
		{
		}

		void CColorConsoleChannel::log(const CMessage& msg)
		{
			CMutex::ScopedLock lock(m_mutex);

			if (m_enableColors)
			{
				int color = m_colors[msg.getPriority()];
				if (color & 0x100)
				{
					m_str << CSI << "1m";
				}
				color &= 0xff;
				m_str << CSI << color << "m";
			}

			m_str << msg.getText();

			if (m_enableColors)
			{
				m_str << CSI << "0m";
			}

			m_str << std::endl;
		}

		void CColorConsoleChannel::setProperty(const std::string& name, const std::string& value)
		{
			if (name == "enableColors")
			{
				m_enableColors = icompare(value, "true") == 0;
			}
			else if (name == "traceColor")
			{
				m_colors[CMessage::PRIO_TRACE] = parseColor(value);
			}
			else if (name == "debugColor")
			{
				m_colors[CMessage::PRIO_DEBUG] = parseColor(value);
			}
			else if (name == "informationColor")
			{
				m_colors[CMessage::PRIO_INFORMATION] = parseColor(value);
			}
			else if (name == "noticeColor")
			{
				m_colors[CMessage::PRIO_NOTICE] = parseColor(value);
			}
			else if (name == "warningColor")
			{
				m_colors[CMessage::PRIO_WARNING] = parseColor(value);
			}
			else if (name == "errorColor")
			{
				m_colors[CMessage::PRIO_ERROR] = parseColor(value);
			}
			else if (name == "criticalColor")
			{
				m_colors[CMessage::PRIO_CRITICAL] = parseColor(value);
			}
			else if (name == "fatalColor")
			{
				m_colors[CMessage::PRIO_FATAL] = parseColor(value);
			}
			else
			{
				CChannel::setProperty(name, value);
			}
		}

		std::string CColorConsoleChannel::getProperty(const std::string& name) const
		{
			if (name == "enableColors")
			{
				return m_enableColors ? "true" : "false";
			}
			else if (name == "traceColor")
			{
				return formatColor(m_colors[CMessage::PRIO_TRACE]);
			}
			else if (name == "debugColor")
			{
				return formatColor(m_colors[CMessage::PRIO_DEBUG]);
			}
			else if (name == "informationColor")
			{
				return formatColor(m_colors[CMessage::PRIO_INFORMATION]);
			}
			else if (name == "noticeColor")
			{
				return formatColor(m_colors[CMessage::PRIO_NOTICE]);
			}
			else if (name == "warningColor")
			{
				return formatColor(m_colors[CMessage::PRIO_WARNING]);
			}
			else if (name == "errorColor")
			{
				return formatColor(m_colors[CMessage::PRIO_ERROR]);
			}
			else if (name == "criticalColor")
			{
				return formatColor(m_colors[CMessage::PRIO_CRITICAL]);
			}
			else if (name == "fatalColor")
			{
				return formatColor(m_colors[CMessage::PRIO_FATAL]);
			}
			else
			{
				return CChannel::getProperty(name);
			}
		}

		CColorConsoleChannel::Color CColorConsoleChannel::parseColor(const std::string& color) const
		{
			if (icompare(color, "default") == 0)
				return CC_DEFAULT;
			else if (icompare(color, "black") == 0)
				return CC_BLACK;
			else if (icompare(color, "red") == 0)
				return CC_RED;
			else if (icompare(color, "green") == 0)
				return CC_GREEN;
			else if (icompare(color, "brown") == 0)
				return CC_BROWN;
			else if (icompare(color, "blue") == 0)
				return CC_BLUE;
			else if (icompare(color, "magenta") == 0)
				return CC_MAGENTA;
			else if (icompare(color, "cyan") == 0)
				return CC_CYAN;
			else if (icompare(color, "gray") == 0)
				return CC_GRAY;
			else if (icompare(color, "darkGray") == 0)
				return CC_DARKGRAY;
			else if (icompare(color, "lightRed") == 0)
				return CC_LIGHTRED;
			else if (icompare(color, "lightGreen") == 0)
				return CC_LIGHTGREEN;
			else if (icompare(color, "yellow") == 0)
				return CC_YELLOW;
			else if (icompare(color, "lightBlue") == 0)
				return CC_LIGHTBLUE;
			else if (icompare(color, "lightMagenta") == 0)
				return CC_LIGHTMAGENTA;
			else if (icompare(color, "lightCyan") == 0)
				return CC_LIGHTCYAN;
			else if (icompare(color, "white") == 0)
				return CC_WHITE;
			else throw InvalidArgumentException("Invalid color value", color);
		}

		std::string CColorConsoleChannel::formatColor(Color color) const
		{
			switch (color)
			{
			case CC_DEFAULT:      return "default";
			case CC_BLACK:        return "black";
			case CC_RED:          return "red";
			case CC_GREEN:        return "green";
			case CC_BROWN:        return "brown";
			case CC_BLUE:         return "blue";
			case CC_MAGENTA:      return "magenta";
			case CC_CYAN:         return "cyan";
			case CC_GRAY:         return "gray";
			case CC_DARKGRAY:     return "darkGray";
			case CC_LIGHTRED:     return "lightRed";
			case CC_LIGHTGREEN:   return "lightGreen";
			case CC_YELLOW:       return "yellow";
			case CC_LIGHTBLUE:    return "lightBlue";
			case CC_LIGHTMAGENTA: return "lightMagenta";
			case CC_LIGHTCYAN:    return "lightCyan";
			case CC_WHITE:        return "white";
			default:              return "invalid";
			}
		}

		void CColorConsoleChannel::initColors()
		{
			m_colors[0] = CC_DEFAULT; // unused
			m_colors[CMessage::PRIO_FATAL]       = CC_LIGHTRED;
			m_colors[CMessage::PRIO_CRITICAL]    = CC_LIGHTRED;
			m_colors[CMessage::PRIO_ERROR]       = CC_LIGHTRED;
			m_colors[CMessage::PRIO_WARNING]     = CC_YELLOW;
			m_colors[CMessage::PRIO_NOTICE]      = CC_DEFAULT;
			m_colors[CMessage::PRIO_INFORMATION] = CC_DEFAULT;
			m_colors[CMessage::PRIO_DEBUG]       = CC_GRAY;
			m_colors[CMessage::PRIO_TRACE]       = CC_GRAY;
		}

	}//end of namespace log
}//end of namespace JHCPP
